// 回调函数详解
// 先看函数指针

// 什么是回调函数？
// 回调函数是一个被传递给另一个函数的函数，这个函数会在某个事件发生或某个条件满足时被"回调"（调用）。

// 简单来说：
//      你提供一个函数（回调函数）
//      把它交给另一个函数（或系统）
//      当特定事件发生时，那个函数（或系统）会调用你提供的函数

// 为什么叫"回调"？
// 名称"回调"来源于调用的方向：
//      通常，你的代码调用库函数
//      而在回调中，库函数调用你的代码
//      这种调用方向的反转，就是"回调"名称的由来

// 回调函数的简单类比
// 想象你去修理店修手机：
// 1.你把手机（任务）交给修理工（函数）
// 2.你留下电话号码（回调函数）
// 3.修理工完成修理后，通过你留下的电话号码联系你（调用回调函数）
// 4.你接到电话后执行后续操作（回调函数的内容）

// C++中的回调函数示例
// 基本示例
#include <iostream>

// 回调函数类型
typedef void (*Callback)(int);

// 接受回调函数的函数
void performTask(int value, Callback onComplete)
{
    // 执行一些操作
    std::cout << "执行任务，处理值: " << value << std::endl;

    // 任务完成，调用回调函数
    onComplete(value * 2);
}

// 回调函数的实现
void taskCompleted(int result)
{
    std::cout << "任务完成，结果是: " << result << std::endl;
}

int main()
{
    // 使用回调
    performTask(5, taskCompleted);

    return 0;
}

// 使用Lambda表达式作为回调
// 在现代C++中，可以使用Lambda表达式作为回调，使代码更简洁：
#include <iostream>
#include <functional>

// 使用std::function代替函数指针
void performTask(int value, std::function<void(int)> onComplete)
{
    std::cout << "执行任务，处理值: " << value << std::endl;
    onComplete(value * 2);
}

int main()
{
    // 使用lambda表达式作为回调
    performTask(5, [](int result)
                { std::cout << "任务完成，结果是: " << result << std::endl; });

    return 0;
}

// 回调函数的实际应用
// 1. 异步操作
// 回调最常见的用途之一是处理异步操作：
void readFileAsync(const std::string &filename, std::function<void(const std::string &)> onSuccess,
                   std::function<void(const std::string &)> onError)
{
    // 在另一个线程中读取文件
    std::thread t([filename, onSuccess, onError]()
                  {
        try {
            // 假设这是读取文件的代码
            std::string content = "文件内容...";
            onSuccess(content);  // 成功时调用
        }
        catch (const std::exception& e) {
            onError(e.what());  // 失败时调用
        } });
    t.detach();
}

// 使用
readFileAsync("data.txt", [](const std::string &content)
              { std::cout << "文件读取成功: " << content << std::endl; }, [](const std::string &error)
              { std::cout << "文件读取失败: " << error << std::endl; });

// 2. 事件处理
// GUI编程中，回调用于处理用户事件：
// 简化的按钮类
class Button
{
public:
    void setOnClickHandler(std::function<void()> handler)
    {
        onClick = handler;
    }

    void click()
    {
        if (onClick)
        {
            onClick(); // 调用回调函数
        }
    }

private:
    std::function<void()> onClick;
};

// 使用
Button saveButton;
saveButton.setOnClickHandler([]()
                             { std::cout << "保存文件" << std::endl; });

// 当用户点击按钮时
saveButton.click(); // 输出: 保存文件

// 回调函数的优势
// 1.解耦：调用者不需要知道被调用者的具体实现
// 2.灵活性：可以在运行时改变行为
// 3.扩展性：可以添加新功能而不修改现有代码
// 4.异步处理：适合处理不立即完成的操作

// 回调函数的挑战
// 1.回调地狱：嵌套多层回调可能导致代码难以理解
// 2.上下文管理：需要小心管理回调函数执行的上下文
// 3.生命周期：确保回调函数在被调用时仍然有效
// 4.错误处理：在回调链中处理错误可能很复杂

// 现代C++中的回调替代方案
// 1.Promise和Future：更结构化的异步编程方式
// 2.协程（C++20）：简化异步代码的编写
// 3.信号槽系统：如Qt的信号槽机制，提供更强的类型安全

// 总结
// 回调函数本质上是一种"控制反转"的机制，它允许你将"做什么"和"何时做"分离。理解回调需要转变思维方式，从"我调用别人"到"别人调用我"。

// 在C++中，回调可以通过函数指针、函数对象、std::function或Lambda表达式实现。现代C++提供了更多工具来处理回调的复杂性，使其更安全、更易于使用。